//
//  XMSHttpChannel.m
//  etionMisc
//
//  Created by wu jingxing on 12-11-21.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "XMSHttpChannel.h"

#import "RequestChannelPool.h"

static NSString*(^s_transferURL)(NSString *URL);

@interface XMSHttpChannel()<NSURLConnectionDelegate>
{
    NSURLConnection* _connect;
    NSMutableURLRequest* _request;
    NSMutableData* _data;
    
    __unsafe_unretained id<XMSHttpChannelDelegate> _delegate;
    
    XMSDispatchQueueWrapper *_delegatequeue;
    
    BOOL _errorResponse;
}

@end

@implementation XMSHttpChannel

@synthesize delegate = _delegate;
@synthesize data = _data;

-(id)initWithURLString:(NSString*)szUrl
{
    self = [super init];
    
    if(s_transferURL != NULL)
        szUrl = s_transferURL(szUrl);

    _request = [[NSMutableURLRequest requestWithURL:[NSURL URLWithString:[szUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30] retain_mm];
    
    _delegatequeue = [[XMSDispatchQueueWrapper alloc]initWithName:""];
    
    self.dispatchQueueWrapper = [[[XMSDispatchQueueWrapper alloc]initWithName:""]autorelease_mm];
    
    return self;
}

-(id)initWithURLRequest:(NSURLRequest*)urlrequest
{
    self = [super init];
    
    _request = [NSMutableURLRequest new];
    [_request setAllHTTPHeaderFields:[urlrequest allHTTPHeaderFields]];
    
    _delegatequeue = [[XMSDispatchQueueWrapper alloc]initWithName:""];
    
    self.dispatchQueueWrapper = [[[XMSDispatchQueueWrapper alloc]initWithName:""]autorelease_mm];
    
    return self;
}

-(void)dealloc
{
    [_connect release_mm];
    [_request release_mm];
    [_data release_mm];
    [_delegatequeue release_mm];
    
    superdealloc_mm;
}

-(void)setDelegate:(id<XMSHttpChannelDelegate>)delegate
{
    [_delegatequeue dispatchThreadSync:^
    {
        _delegate = delegate;
    }];
}

-(void)setHTTPHeaderFields:(NSDictionary*)dicHeader
{
    [_request setAllHTTPHeaderFields:dicHeader];
}

-(void)setHTTPMethod:(NSString*)szMethod
{
    [_request setHTTPMethod:szMethod];
}
-(void)setHTTPDeleteMethod
{
    [_request setHTTPMethod:@"DELETE"];
}

-(void)setHTTPPutMethod
{
    [_request setHTTPMethod:@"PUT"];
}

-(void)setHTTPGetMethod
{
    [_request setHTTPMethod:@"GET"];
}

-(void)setHTTPPostMethod
{
    [_request setHTTPMethod:@"POST"];
}

-(void)setHTTPBody:(NSString*)szBody
{
    [_request setHTTPBody:[szBody dataUsingEncoding:NSUTF8StringEncoding]];
}

-(void)setHTTPDataBody:(NSData*)body
{
    [_request setHTTPBody:body];
}

-(void)_startRequest
{
    _connect=[[NSURLConnection alloc] initWithRequest:_request delegate:self];
}

-(BOOL)startRequest
{
//    [self.channelPool addRequestChannelPoolRunLoopTread:^(NSThread *thread) 
//    {
//        [self performSelector:@selector(_startRequest) onThread:thread withObject:nil waitUntilDone:NO];
//    }];
    
    BOOL bResult=FALSE;
    
    if(self.isCanRequest != YES)
        return bResult;
    
    bResult = [self.channelPool addRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
    {
        _connect=[[NSURLConnection alloc] initWithRequest:_request delegate:self startImmediately:NO];
        [_connect scheduleInRunLoop:runloop forMode:NSDefaultRunLoopMode];
        [_connect start];
    }];
    
    return bResult;
}

-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
{
    [self dispatchQueueRunType:EDispatchQueueRunTypeAsync checkTerminate:YES asyncBlock:^
    {
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)aResponse;
        
        NSInteger nErrorcode=[httpResponse statusCode];
        (void)nErrorcode;
        
        _data = [NSMutableData new];
        
//        if(2 == nErrorcode/100)
//        {
//            _data=[NSMutableData new];
//        }
//        else
//        {
//            _errorResponse = YES;
//            
//            NSString *s = [NSHTTPURLResponse localizedStringForStatusCode:nErrorcode];
//            NSError *error=[NSError errorWithDomain:s code:nErrorcode userInfo:nil];
//            [_connect cancel];
//            [self.channelPool removeRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
//            {
//                [_connect unscheduleFromRunLoop:runloop forMode:NSDefaultRunLoopMode];
//            }];
//            [_delegatequeue dispatchThreadAsync:^
//            {
//                [_delegate HTTPOperateResult:self type:XMSHTTPOperateResultTypeRecvResponseError result:nErrorcode error:error];
//            }];
//        }
        
        if(nErrorcode == 401)
        {
            _errorResponse = YES;
            
            NSString *s = [NSHTTPURLResponse localizedStringForStatusCode:nErrorcode];
            NSError *error=[NSError errorWithDomain:s code:nErrorcode userInfo:nil];
            [_connect cancel];
            [self.channelPool removeRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
            {
                [_connect unscheduleFromRunLoop:runloop forMode:NSDefaultRunLoopMode];
            }];
            [_delegatequeue dispatchThreadAsync:^
            {
                [_delegate HTTPOperateResult:self type:XMSHTTPOperateResultTypeRecvResponseError result:nErrorcode error:error];
            }];
        }

    }];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
{
    [self dispatchQueueRunType:EDispatchQueueRunTypeAsync checkTerminate:YES asyncBlock:^
    {
        [_data appendData:theData];
    }];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [self dispatchQueueRunType:EDispatchQueueRunTypeAsync checkTerminate:YES asyncBlock:^
    {
        if(_errorResponse == YES)
        {
            _errorResponse = NO;
            return ;
        }
        
        [_connect cancel];
        [self.channelPool removeRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
        {
            [_connect unscheduleFromRunLoop:runloop forMode:NSDefaultRunLoopMode];
        }];
        [_delegatequeue dispatchThreadAsync:^
        {
             [_delegate HTTPOperateResult:self type:XMSHTTPOperateResultTypeFinish result:YES error:nil];
        }];
    }];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [self dispatchQueueRunType:EDispatchQueueRunTypeAsync checkTerminate:YES asyncBlock:^
    {
        [_connect cancel];
        [self.channelPool removeRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
        {
            [_connect unscheduleFromRunLoop:runloop forMode:NSDefaultRunLoopMode];
        }];
        [_delegatequeue dispatchThreadAsync:^
        {
            [_delegate HTTPOperateResult:self type:XMSHTTPOperateResultTypeFail result:error.code error:error];
        }];
    }];
}

-(void)cancelRequest
{
    [super terminateRequest];
}

-(BOOL)terminateSelfRequest:(BOOL)bRejectrequest
{
    [self dispatchQueueRunType:EDispatchQueueRunTypeAsync checkTerminate:NO asyncBlock:^
    {
        [_connect cancel];
        [self.channelPool removeRequestChannelPoolRunLoop:^(NSRunLoop *runloop)
        {
            [_connect unscheduleFromRunLoop:runloop forMode:NSDefaultRunLoopMode];
        }];
    }];
    [_delegatequeue dispatchThreadSync:^
    {
        [_delegate HTTPOperateResult:self type:XMSHTTPOperateResultTypeTerminate result:TERMINATEREADWRITE error:nil];
    }];
    return YES;
}


-(BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection
{
    return YES;
}

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [[challenge sender] useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    }
}

@end

@implementation NSMutableDictionary (XMSHttpChannel)

-(void)setContentLengthValue:(NSString*)szValue
{
    [self setValue:szValue forKey:@"Content-Length"];
}

-(void)setContentTypeValue:(NSString*)szValue
{
    [self setValue:szValue forKey:@"Content-Type"];
}

@end

@implementation XMSHttpChannel (TransferURL)

+(void)operateNeedTransferURLBlock:(NSString*(^)(NSString *URL))transferURL
{
    if(s_transferURL != NULL)
        Block_release(s_transferURL);
    s_transferURL = NULL;
    if(transferURL != NULL)
        s_transferURL = Block_copy(transferURL);
}

@end
